//
//  NSAttributedString_additions.m
//  ShapeShifter
//
//  Created by Jason Harris on 8/8/04.
//  Copyright (c) 2006, Jason Harris and Geekspiff
//  All rights reserved.
//  
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided
//  that the following conditions are met:
//  
//  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//  following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list
//  of conditions and the following disclaimer in the documentation and/or other materials provided with the
//  distribution. Neither the name of Jason Harris, Geekspiff, nor the names of its contributors may be used
//  to endorse or promote products derived from this software without specific prior written permission.
//  
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
//  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
//  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//  POSSIBILITY OF SUCH DAMAGE.
//

#import "NSAttributedString_additions.h"


@implementation NSAttributedString (ShapeShifter_Additions)

- (NSAttributedString *)attributedStringForWidth: (float)width
{
	static float const kMaxKerning = -1.0;
	
	NSSize size = [self size];
	if ( size.width <= width )
		return self;
	
	NSMutableDictionary *attributes = (NSMutableDictionary *)[self attributesAtIndex: 0 effectiveRange: NULL];
	if ( ! attributes )
		attributes = [NSMutableDictionary dictionary];
	if ( ! [attributes isKindOfClass: [NSMutableDictionary class]] )
		attributes = [NSMutableDictionary dictionaryWithDictionary: attributes];
	
	NSString *string = [self string];
	float kerning = -0.1;
	
	while ( kerning > kMaxKerning )
	{
		[attributes setObject: [NSNumber numberWithFloat: kerning] forKey: NSKernAttributeName];
		NSAttributedString *newString = [[NSAttributedString alloc] initWithString: string attributes: attributes];
		size = [newString size];
		if ( size.width <= width )
		{
			[newString autorelease];
			return newString;
		}
		[newString release];
		kerning -= 0.1;
	}
	[attributes removeObjectForKey: NSKernAttributeName];
	
	NSArray *components = [string componentsSeparatedByString: @" "];
	int componentCount = [components count];
	int removeCount = 1;
	while ( removeCount < componentCount )
	{
		static unichar ellipse[] = {0x2026};
		static NSString *ellipseString = nil;
		if ( ! ellipseString )
			ellipseString = [[NSString alloc] initWithCharacters: ellipse length: 1];
		
		NSArray *prefix = nil;
		NSArray *suffix = nil;
		NSRange removeRange = NSMakeRange( floor((componentCount - removeCount) / 2.0 + 0.5), removeCount );
		int prefixEnd = removeRange.location;
		if ( prefixEnd > 0 )
			prefix = [components subarrayWithRange: NSMakeRange(0, prefixEnd)];
		int suffixStart = removeRange.location + removeRange.length;
		if ( suffixStart < componentCount )
		{
			int suffixLength = componentCount - suffixStart;
			suffix = [components subarrayWithRange: NSMakeRange(suffixStart, suffixLength)];
		}
		NSString *prefixString = [prefix componentsJoinedByString: @" "];
		NSString *suffixString = [suffix componentsJoinedByString: @" "];
		NSString *chars = [NSString stringWithFormat: @"%@%@%@", prefixString, ellipseString, suffixString];
		
		NSAttributedString *newString = [[NSAttributedString alloc] initWithString: chars attributes: attributes];
		size = [newString size];
		if ( size.width <= width )
		{
			[newString autorelease];
			return newString;
		}
		[newString release];
		++removeCount;
	}
	
	return self;
}

@end
